Chapter 10 - Dictionaries

This notebook uses code snippets and explanation from this course

The last type of container we will introduce in this topic is dictionaries. Programming is mostly about solving real-world problems as efficiently as possible, but it is also important to write and organize code in a human readable fashion. A dictionary offers a kind of abstraction that comes in handy a lot of times: it is a type of "associative memory" or key:value storage. It allows you to describe two pieces of data and their relationship.

At the end of this chapter, you will:

  • understand the relevance of dictionaries
  • know how to create a dictionary
  • know how to add items to a dictionary
  • know how to inspect/extract items from a dictionary
  • know how to count with a dictionary
  • know how to create nested dictionaries

If you want to learn more about these topics, you might find the following links useful:

If you have questions about this chapter, please refer to the forum on Canvas.

1. Dictionaries

Imagine that you are a teacher and you've graded exams (everyone got high grades of course). You would like to store this information in a way that you can simply ask the program for the grade of a particular student. After some thought, you first try to accomplish this using a list.


In [ ]:
student_grades = ['Frank', 8, 'Susan', 7, 'Guido', 10]

In [ ]:
student = 'Frank'
index_of_student = student_grades.index(student) # we use the index method (list.index)
print('grade of', student, 'is', student_grades[index_of_student + 1])

However, you're not happy about the solution. Every time you request a grade, we need to first determine the position of the student in the list and then use that index + 1 to obtain the grade. That's pretty inefficient. The take home message here is that lists are not really good if we want two pieces of information together. Dictionaries for the rescue!


In [ ]:
student_grades = {'Frank': 8, 'Susan': 7, 'Guido': 10}

In [ ]:
student_grades['Frank']

2. How to create a dictionary

Let's take another look at the student_grades dictionary.


In [ ]:
student_grades = {'Frank': 8, 'Susan': 7, 'Guido': 10}
  • a dictionary is surrounded by curly brackets and the key/value pairs are separated by commas.
  • A dictionary consists of one or more key:value pairs, the key is the 'identifier' or "name" that is used to describe the value.
  • the keys in a dictionary are unique
  • the syntax for a key/value pair is: KEY : VALUE
  • the keys (e.g. 'Frank') in a dictionary have to be immutable
  • the values (e.g. 8) in a dictionary can by any python object
  • a dictionary can be empty

Please note that keys in a dictionary have to immutable.

This works (strings as keys)


In [ ]:
student_grades = {'Frank': 8, 'Susan': 7, 'Guido': 10}

This does not (list as keys)


In [ ]:
a_dict = {['a', 'list']: 8}

Please note that the values in a dictionary can by any python object

This works (integers as values)


In [ ]:
a_dict = {'Frank': 8, 'Susan': 7}

But this as well (lists as values)


In [ ]:
another_dict = {'Frank' : [8], 'Susan' : [7]}

Please note that a dictionary can be empty (use dict()):


In [ ]:
an_empty_dict = dict()
another_empty_dict = {} # This works too, but it is less readable and confusing (looks similar to sets)
print(type(another_empty_dict), type(an_empty_dict))

3. How to add items to a dictionary

There is one very simple way in order to add a key:value pair to a dictionary. Please look at the following code snippet:


In [ ]:
a_dict = dict()
print(a_dict)

In [ ]:
a_dict['Frank'] = 8
print(a_dict)

Please note that dictionary keys should be unique identifiers for the values in the dictionary. Key:value pairs get overwritten if you assign a different value to an existing key.


In [ ]:
a_dict = dict()
a_dict['Frank'] = 8
print(a_dict)
a_dict['Frank'] = 7
print(a_dict)
a_dict['Frank'] = 9
print(a_dict)

4. How to access data in a dictionary

The most basic operation on a dictionary is a look-up. Simply enter the key and the dictionary returns the value.


In [ ]:
student_grades = {'Frank': 8, 'Susan': 7, 'Guido': 10}

In [ ]:
print(student_grades['Frank'])

If the key is not in the dictionary, it will return a KeyError.


In [ ]:
student_grades['Piet']

In order to avoid getting an error, you can use an if-statement


In [ ]:
key = 'Piet'
if key in student_grades:
    print(student_grades[key])
else:
    print(key, 'not in dictionary')

In [ ]:
key = 'Frank'
if key in student_grades:
    print(student_grades[key])
else:
    print(key, 'not in dictionary')

the keys method returns the keys in a dictionary


In [ ]:
student_grades = {'Frank': 8, 'Susan': 7, 'Guido': 10}

In [ ]:
the_keys = student_grades.keys()
print(the_keys)

the values method returns the values in a dictionary


In [ ]:
the_values = student_grades.values()
print(the_values)

We can use the built-in functions to inspect the keys and values. For example:


In [ ]:
the_values = student_grades.values()
print(len(the_values)) # number of values in a dict
print(max(the_values)) # highest value of values in a dict
print(min(the_values)) # lowest value of values in a dict
print(sum(the_values)) # sum of all values of values in a dict

However, what if we want to know which students got a 8 or higher? The items method is very useful for this scenario. Please carefully look at the following code snippet.


In [ ]:
student_grades = {'Frank': 8, 'Susan': 7, 'Guido': 10}
print(student_grades.items())

The items method returns a list of tuples. We can combine what we have learnt about looping and tuples to access the keys (the students' names) and values (their grades):


In [ ]:
for key, value in student_grades.items(): # please note the tuple unpacking
    print(key, value)

This also makes it possible to detect which students obtained a grade of 8 or higher.


In [ ]:
for student, grade in student_grades.items():
    if grade > 7:
        print(student, grade)

5. Counting with a dictionary

Dictionaries are very useful to derive statistics. For example, we can easily determine the frequency of each letter in a word.


In [ ]:
letter2freq = dict()
word = 'hippo'

for letter in word: 
    
    if letter in letter2freq: # add 1 to the dictionary if the keys exists
        letter2freq[letter] += 1 # note: x +=1 does the same as x = x + 1
    else:
        letter2freq[letter] = 1 # set default value to 1 if key does not exists 

    print(letter, letter2freq)
    
print()
print(letter2freq)

You can do this as well with lists


In [ ]:
a_sentence = ['Obama', 'was', 'the', 'president', 'of', 'the', 'USA']
word2freq = dict()

for word in a_sentence: 
    
    if word in word2freq: # add 1 to the dictionary if the keys exists
        word2freq[word] += 1 
    else:
        word2freq[word] = 1 # set default value to 1 if key does not exists 

    print(word, word2freq)

print()
print(word2freq)

Python actually has a module, which is very useful for counting. It's called collections.


In [ ]:
from collections import Counter

In [ ]:
word_freq = Counter(['Obama', 'was', 'the', 'president', 'of', 'the', 'USA'])
print(word_freq)

Feel free to start using this module after the assignment of this block.

6. Nested dictionaries

Since dictionaries consists of key:value pairs, we can actually make another dictionary the value of a dictionary.


In [ ]:
a_nested_dictionary = {'a_key': 
                       {'nested_key1': 1,
                        'nested_key2': 2,
                        'nested_key3': 3}
                      }
print(a_nested_dictionary)

Please note that the value is in fact a dictionary:


In [ ]:
print(a_nested_dictionary['a_key'])

In order to access the nested value, we must do a look up for each key on each nested level


In [ ]:
the_nested_value = a_nested_dictionary['a_key']['nested_key1']
print(the_nested_value)

Practice questions:

What do sets and dictionaries have in common?
What do lists and tuples have in common?
Can you add things to a list?
Can you add things to a tuples?

An overview:

property set list tuple dict keys dict values
mutable (can you add add/remove?) yes yes no yes yes
can contain duplicates no yes yes no yes
ordered no yes yes yes, but do not rely on it depends on type of value
finding element(s) quick slow slow quick depends on type of value
can contain immutables all all immutable all

Exercises

Exercise 1:

You are tying to keep track of your groceries using a python dictionary. Please add 'tomatoes', 'bread', 'chocolate bars' and 'pineapples' to your shopping dictionary and assign values according to how many items of each you would like to by.


In [ ]:
# your code here

Exercise 2:

Print the number of pineapples you would like to buy by using only one line of code and without printing the entire dictionary.


In [ ]:
# your code here

Exercise 3:

Use a loop and unpacking to print the items and numbers on your shopping list in the following format:

Item: [Item], number: [number]

e.g. Item: tomatoes, number: 3


In [ ]:
# you code here

Exercise 4:

Which container would you use to count the frequency of each word in a text?


In [ ]: